#include "SdioInitHelper.h"

#include <string.h>

// SDIO控制句柄
stc_sd_handle_t SdHandle;

// 未来改成缓冲区
uint8_t u8WriteBlocks[SD_CARD_BLK_SIZE * SD_CARD_BLK_NUM];
uint8_t u8ReadBlocks[SD_CARD_BLK_SIZE * SD_CARD_BLK_NUM];
__IO uint8_t u8TxCompleteFlag = 0U, u8RxCompleteFlag = 0U, u8TxRxErrorFlag = 0U;

/**
 * @brief  SDIOC transfer complete interrupt callback function.
 * @param  None
 * @retval None
 */
void SdCard_TransCompleteIrqCallback(void)
{
    SD_IRQHandler(&SdHandle);
}

/**
 * @brief  SDIOC TX complete callback function.
 * @param  None
 * @retval None
 */
void SD_TxCompleteCallback(stc_sd_handle_t *handle)
{
    u8TxCompleteFlag = 1U;
}

/**
 * @brief  SDIOC RX complete callback function.
 * @param  None
 * @retval None
 */
void SD_RxCompleteCallback(stc_sd_handle_t *handle)
{
    u8RxCompleteFlag = 1U;
}

/**
 * @brief  SDIOC error callback function.
 * @param  None
 * @retval None
 */
void SD_ErrorCallback(stc_sd_handle_t *handle)
{
    u8TxRxErrorFlag = 1U;
}


/**
 * @brief  SD card configuration.
 * @param  None
 * @retval None
 */
void SdCard_Config(void)
{
    /* Enable SDIOC clock */
    FCG_Fcg1PeriphClockCmd(FCG1_PERIPH_SDIOC1, ENABLE);
    /* Configure structure initialization */
    SdHandle.SDIOCx                     = CM_SDIOC1;
    SdHandle.stcSdiocInit.u32Mode       = SDIOC_MD_SD;
    SdHandle.stcSdiocInit.u8CardDetect  = SDIOC_CARD_DETECT_CD_PIN_LVL;
    SdHandle.stcSdiocInit.u8SpeedMode   = SDIOC_SPEED_MD_HIGH;
    SdHandle.stcSdiocInit.u8BusWidth    = SDIOC_BUS_WIDTH_4BIT;
    SdHandle.stcSdiocInit.u16ClockDiv   = SDIOC_CLK_DIV4;

    SdHandle.DMAx      = CM_DMA1;
    SdHandle.u8DmaTxCh = DMA_CH6;
    SdHandle.u8DmaRxCh = DMA_CH5;


    /* Reset and init SDIOC */
    if (LL_OK != SDIOC_SWReset(SdHandle.SDIOCx, SDIOC_SW_RST_ALL)) {
        DDL_Printf("Reset SDIOC failed!\r\n");
    } else if (LL_OK != SD_Init(&SdHandle)) {
        DDL_Printf("SD card initialize failed!\r\n");
    } else {
    }
	
//	else if (SET != SdCard_GetInsertState()) {
//        DDL_Printf("No SD card insertion!\r\n");
//    } 
}

//en_flag_status_t SdCard_GetInsertState(void)
//{
//    en_flag_status_t enFlagSta = SET;

//    /* Check SD card detect pin */
//    if (GPIO_ReadInputPins(RTC_INT_PORT, RTC_INT_PIN) == PIN_SET) {
//        enFlagSta = RESET;
//    }

//    return enFlagSta;
//}

int32_t SD_Init(stc_sd_handle_t *handle) {
	int32_t i32Ret;
    stc_sdioc_init_t stcSdInit;
	
	if (NULL == handle) {
        i32Ret = LL_ERR_INVD_PARAM;
    } else {
		// 进入初始化阶段。需要先给系统降频
		LL_PERIPH_WE(LL_PERIPH_ALL);
		CLK_SetClockDiv(CLK_BUS_EXCLK, (CLK_EXCLK_DIV4));
		LL_PERIPH_WP(LL_PERIPH_ALL);
		// 进入低速卡识别模式
		stcSdInit.u16ClockDiv   = SDIOC_CLK_DIV256;
        stcSdInit.u32Mode       = handle->stcSdiocInit.u32Mode;
        stcSdInit.u8CardDetect  = handle->stcSdiocInit.u8CardDetect;
		/* Set Power State to ON */
        SDIOC_PowerCmd(handle->SDIOCx, ENABLE);
		
		/* Initialize SDIOC with default configure */
        (void)SDIOC_Init(handle->SDIOCx, &stcSdInit);
        /* Wait for the SDIOC to initialization */
        rt_thread_mdelay(2);
		
		/* Identify card operating voltage */
        i32Ret = SD_PowerCmd(handle, ENABLE);
        if (LL_OK != i32Ret) {
            return i32Ret;
        }
        /* Card initialization */
        i32Ret = SD_InitCard(handle);
        if (LL_OK != i32Ret) {
            return i32Ret;
        }
        /* Get SCR Register */
        i32Ret = SD_GetSCR(handle, handle->u32SCR);
        if (LL_OK != i32Ret) {
            return i32Ret;
        }
        /* Configure SD Bus width */
        i32Ret = SD_SetBusWidth(handle);
        if (LL_OK != i32Ret) {
            return i32Ret;
        }
		
        /* Configure SD High speed mode */
        i32Ret = SD_SetSpeedMode(handle);
		// 初始化完毕高速模式，将工作时钟升高。
		LL_PERIPH_WE(LL_PERIPH_ALL);
		CLK_SetClockDiv(CLK_BUS_EXCLK, (CLK_EXCLK_DIV2));
		LL_PERIPH_WP(LL_PERIPH_ALL);

        /* Initialize the error code */
        handle->u32ErrorCode = SDMMC_ERR_NONE;
        /* Initialize the SD operation */
        handle->u32Context = SD_CONTEXT_NONE;
	}
	return i32Ret;
}

/**
 * @brief  Enable or disable SD power.
 * @note   At the power-on, Enquires cards about their operating voltage and configures
 *         clock controls and stores SD information.
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @param  [in] enNewState              An @ref en_functional_state_t enumeration value.
 * @retval int32_t:
 *           - LL_OK: Enable or disable SD power success
 *           - LL_ERR: Refer to u32ErrorCode for the reason of error
 *           - LL_ERR_INVD_PARAM: An invalid parameter was write to the send command
 *           - LL_ERR_TIMEOUT: Send command timeout
 */
int32_t SD_PowerCmd(stc_sd_handle_t *handle, en_functional_state_t enNewState)
{
    uint32_t u32Response = 0UL, u32PowerSta = 0UL;
    __IO uint32_t u32Count = 0UL;
    int32_t i32Ret = LL_OK;

    if (DISABLE != enNewState) {
        /* CMD0: GO_IDLE_STATE */
        i32Ret = SDMMC_CMD0_GoIdleState(handle->SDIOCx, &handle->u32ErrorCode);
        if (LL_OK != i32Ret) {
            return i32Ret;
        }
        /* Wait for reset to completed */
        DDL_DelayMS(1U);
        /* CMD8: SEND_IF_COND: Command available only on V2.0 cards */
        i32Ret = SDMMC_CMD8_SendInterfaceCond(handle->SDIOCx, &handle->u32ErrorCode);
        if (LL_OK != i32Ret) {
            handle->stcSdCardInfo.u32CardVersion = SD_CARD_V1_X;
            /* Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */
            while (0UL == u32PowerSta) {
                if (u32Count++ >= SDMMC_MAX_VOLT_TRIAL) {
                    handle->u32ErrorCode |= SDMMC_ERR_INVD_VOLT;
                    return LL_ERR;
                }

                /* SEND CMD55 APP_CMD with RCA as 0 */
                i32Ret = SDMMC_CMD55_AppCmd(handle->SDIOCx, 0UL, &handle->u32ErrorCode);
                if (LL_OK != i32Ret) {
                    handle->u32ErrorCode |= SDMMC_ERR_UNSUPPORT_FEATURE;
                    return LL_ERR;
                }
                /* Send ACMD41 */
                i32Ret = SDMMC_ACMD41_SendOperateCond(handle->SDIOCx, SDMMC_OCR_STD_CAPACITY,
                                                      &handle->u32ErrorCode);
                if (LL_OK != i32Ret) {
                    handle->u32ErrorCode |= SDMMC_ERR_UNSUPPORT_FEATURE;
                    return LL_ERR;
                }

                /* Get command response */
                (void)SDIOC_GetResponse(handle->SDIOCx, SDIOC_RESP_REG_BIT0_31, &u32Response);
                /* Get Card power up status bit (busy) */
                u32PowerSta = (((u32Response >> 31U) == 1UL) ? 1UL : 0UL);
            }
            /* Card type is SDSC */
            handle->stcSdCardInfo.u32CardType = SD_CARD_SDSC;
        } else {
            handle->stcSdCardInfo.u32CardVersion = SD_CARD_V2_X;
            /* Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */
            while (0UL == u32PowerSta) {
                if (u32Count++ >= SDMMC_MAX_VOLT_TRIAL) {
                    handle->u32ErrorCode |= SDMMC_ERR_INVD_VOLT;
                    return LL_ERR;
                }

                /* SEND CMD55 APP_CMD with RCA as 0 */
                i32Ret = SDMMC_CMD55_AppCmd(handle->SDIOCx, 0UL, &handle->u32ErrorCode);
                if (LL_OK != i32Ret) {
                    return i32Ret;
                }
                /* Send ACMD41 */
                i32Ret = SDMMC_ACMD41_SendOperateCond(handle->SDIOCx, SDMMC_OCR_HIGH_CAPACITY, &handle->u32ErrorCode);
                if (LL_OK != i32Ret) {
                    return i32Ret;
                }
                /* Get command response */
                (void)SDIOC_GetResponse(handle->SDIOCx, SDIOC_RESP_REG_BIT0_31, &u32Response);
                /* Get Card power up status bit (busy) */
                u32PowerSta = (((u32Response >> 31U) == 1UL) ? 1UL : 0UL);
            }

            if (SDMMC_OCR_HIGH_CAPACITY == (u32Response & SDMMC_OCR_HIGH_CAPACITY)) {
                handle->stcSdCardInfo.u32CardType = SD_CARD_SDHC_SDXC;
            } else {
                handle->stcSdCardInfo.u32CardType = SD_CARD_SDSC;
            }
        }
    } else {
        /* Set Power State to OFF */
        SDIOC_ClockCmd(handle->SDIOCx, DISABLE);
        SDIOC_PowerCmd(handle->SDIOCx, DISABLE);
    }

    return i32Ret;
}

/**
 * @brief  Initializes the sd card.
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @retval int32_t:
 *           - LL_OK: SD card Initialize success
 *           - LL_ERR: Refer to u32ErrorCode for the reason of error
 *           - LL_ERR_INVD_PARAM: An invalid parameter was write to the send command
 *           - LL_ERR_TIMEOUT: Send command timeout
 */
int32_t SD_InitCard(stc_sd_handle_t *handle)
{
    int32_t i32Ret;
    uint16_t u16RcaVal = 0U;
    uint32_t u32TempBuffer[4];

    /* Check the power State */
    if (DISABLE == SDIOC_GetPowerState(handle->SDIOCx)) {
        handle->u32ErrorCode |= SDMMC_ERR_REQ_NOT_APPLICABLE;
        return LL_ERR;
    }

    if (SD_CARD_SECURED != handle->stcSdCardInfo.u32CardType) {
        /* Send CMD2 ALL_SEND_CID */
        i32Ret = SDMMC_CMD2_AllSendCID(handle->SDIOCx, &handle->u32ErrorCode);
        if (LL_OK != i32Ret) {
            return i32Ret;
        }
        /* Get Card identification number data */
        (void)SDIOC_GetResponse(handle->SDIOCx, SDIOC_RESP_REG_BIT0_31,   &u32TempBuffer[0]);
        (void)SDIOC_GetResponse(handle->SDIOCx, SDIOC_RESP_REG_BIT32_63,  &u32TempBuffer[1]);
        (void)SDIOC_GetResponse(handle->SDIOCx, SDIOC_RESP_REG_BIT64_95,  &u32TempBuffer[2]);
        (void)SDIOC_GetResponse(handle->SDIOCx, SDIOC_RESP_REG_BIT96_127, &u32TempBuffer[3]);
        handle->u32CID[0] = (u32TempBuffer[0] << 8U);
        handle->u32CID[1] = (u32TempBuffer[1] << 8U) | ((u32TempBuffer[0] >> 24U) & 0xFFU);
        handle->u32CID[2] = (u32TempBuffer[2] << 8U) | ((u32TempBuffer[1] >> 24U) & 0xFFU);
        handle->u32CID[3] = (u32TempBuffer[3] << 8U) | ((u32TempBuffer[2] >> 24U) & 0xFFU);
        /* Send CMD3 SET_REL_ADDR with argument 0 */
        /* SD Card publishes its RCA */
        i32Ret = SDMMC_CMD3_SendRelativeAddr(handle->SDIOCx, &u16RcaVal, &handle->u32ErrorCode);
        if (LL_OK != i32Ret) {
            return i32Ret;
        }
        /* Get the SD card RCA */
        handle->stcSdCardInfo.u32RelativeCardAddr = u16RcaVal;
        /* Send CMD9 SEND_CSD with argument as card's RCA */
        i32Ret = SDMMC_CMD9_SendCSD(handle->SDIOCx, (uint32_t)(handle->stcSdCardInfo.u32RelativeCardAddr << 16U),
                                    &handle->u32ErrorCode);
        if (LL_OK != i32Ret) {
            return i32Ret;
        }
        /* Get Card Specific Data */
        (void)SDIOC_GetResponse(handle->SDIOCx, SDIOC_RESP_REG_BIT0_31,   &u32TempBuffer[0]);
        (void)SDIOC_GetResponse(handle->SDIOCx, SDIOC_RESP_REG_BIT32_63,  &u32TempBuffer[1]);
        (void)SDIOC_GetResponse(handle->SDIOCx, SDIOC_RESP_REG_BIT64_95,  &u32TempBuffer[2]);
        (void)SDIOC_GetResponse(handle->SDIOCx, SDIOC_RESP_REG_BIT96_127, &u32TempBuffer[3]);
        handle->u32CSD[0] = (u32TempBuffer[0] << 8U);
        handle->u32CSD[1] = (u32TempBuffer[1] << 8U) | ((u32TempBuffer[0] >> 24U) & 0xFFU);
        handle->u32CSD[2] = (u32TempBuffer[2] << 8U) | ((u32TempBuffer[1] >> 24U) & 0xFFU);
        handle->u32CSD[3] = (u32TempBuffer[3] << 8U) | ((u32TempBuffer[2] >> 24U) & 0xFFU);
    }

    /* Get the Card Class */
    handle->stcSdCardInfo.u32Class = handle->u32CSD[2] >> 20U;
    /* Get CSD parameters */
    (void)SD_ExtractCardCSD(handle);
    /* Select the Card */
    i32Ret = SDMMC_CMD7_SelectDeselectCard(handle->SDIOCx, (uint32_t)(handle->stcSdCardInfo.u32RelativeCardAddr << 16U),
                                           &handle->u32ErrorCode);
    if (LL_OK != i32Ret) {
        return i32Ret;
    }

    return i32Ret;
}

/**
 * @brief  Extract information of the card which CSD register.
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @retval int32_t:
 *           - LL_OK: Get sd card CSD register success
 *           - LL_ERR: Refer to u32ErrorCode for the reason of error
 */
int32_t SD_ExtractCardCSD(stc_sd_handle_t *handle)
{
    int32_t i32Ret = LL_OK;
    uint32_t u32Temp;
    stc_sd_card_csd_t stcCardCSD;

    stcCardCSD.u8ReadBlockLen = (uint8_t)((handle->u32CSD[2] & 0x000F0000U) >> 16U);
    if (SD_CARD_SDSC == handle->stcSdCardInfo.u32CardType) {
        u32Temp = (uint8_t)((handle->u32CSD[1] & 0xFF000000U) >> 24U);
        stcCardCSD.u32DeviceSize    = (uint32_t)(((handle->u32CSD[2] & 0x000003FFU) << 2U) | ((u32Temp & 0xC0U) >> 6U));
        u32Temp = (uint8_t)((handle->u32CSD[1] & 0x00FF0000U) >> 16U);
        stcCardCSD.u8DeviceSizeMul  = (uint8_t)((u32Temp & 0x03U) << 1U);
        u32Temp = (uint8_t)((handle->u32CSD[1] & 0x0000FF00U) >> 8U);
        stcCardCSD.u8DeviceSizeMul  |= (uint8_t)((u32Temp & 0x80U) >> 7U);

        handle->stcSdCardInfo.u32BlockNum     = (stcCardCSD.u32DeviceSize + 1U) ;
        handle->stcSdCardInfo.u32BlockNum     *= (1UL << (stcCardCSD.u8DeviceSizeMul + 2U));
        handle->stcSdCardInfo.u32BlockSize    = 1UL << (stcCardCSD.u8ReadBlockLen);
        if (handle->stcSdCardInfo.u32BlockSize >= 512U) {
            handle->stcSdCardInfo.u32LogBlockNum = handle->stcSdCardInfo.u32BlockNum *
                                                   (handle->stcSdCardInfo.u32BlockSize / 512U);
        } else {
            handle->stcSdCardInfo.u32LogBlockNum = (handle->stcSdCardInfo.u32BlockNum / 512U) *
                                                   handle->stcSdCardInfo.u32BlockSize;
        }
        handle->stcSdCardInfo.u32LogBlockSize = 512UL;
    } else if (SD_CARD_SDHC_SDXC == handle->stcSdCardInfo.u32CardType) {
        stcCardCSD.u32DeviceSize = (uint32_t)(((handle->u32CSD[2] & 0x0000003FU) << 16U) |
                                              ((handle->u32CSD[1] & 0xFFFF0000U) >> 16U));

        handle->stcSdCardInfo.u32BlockNum     = (stcCardCSD.u32DeviceSize + 1U) * 1024U;
        handle->stcSdCardInfo.u32BlockSize    = 512U;
        handle->stcSdCardInfo.u32LogBlockNum  = handle->stcSdCardInfo.u32BlockNum;
        handle->stcSdCardInfo.u32LogBlockSize = handle->stcSdCardInfo.u32BlockSize;
    } else {
        handle->u32ErrorCode |= SDMMC_ERR_UNSUPPORT_FEATURE;
        return LL_ERR;
    }

    return i32Ret;
}

/**
 * @brief  Get the SD card SCR register value.
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @param  [out] pu32SCR                Pointer to the value of SD card SCR register
 * @retval int32_t:
 *           - LL_OK: Get the SCR register value success
 *           - LL_ERR: Refer to u32ErrorCode for the reason of error
 *           - LL_ERR_INVD_PARAM: An invalid parameter was write to the send command
 *           - LL_ERR_TIMEOUT: Send command timeout
 */
int32_t SD_GetSCR(stc_sd_handle_t *handle, uint32_t pu32SCR[])
{
    stc_sdioc_data_config_t stcDataCfg;
    int32_t i32Ret;
    uint32_t u32CardSta = 0UL;
    uint32_t u32TempSCR[2] = {0UL, 0UL};

    /* Check the lock status */
    i32Ret = SD_GetCurrCardStatus(handle, &u32CardSta);
    if (LL_OK != i32Ret) {
        return i32Ret;
    }
    if (SDMMC_STATUS_CARD_IS_LOCKED == (u32CardSta & SDMMC_STATUS_CARD_IS_LOCKED)) {
        handle->u32ErrorCode |= SDMMC_ERR_LOCK_UNLOCK_FAILED;
        return LL_ERR;
    }

    /* Set Block Size To 8 Bytes */
    i32Ret = SDMMC_CMD16_SetBlockLength(handle->SDIOCx, 8UL, &handle->u32ErrorCode);
    if (LL_OK != i32Ret) {
        return i32Ret;
    }
    /* Send CMD55 APP_CMD with argument as card's RCA */
    i32Ret = SDMMC_CMD55_AppCmd(handle->SDIOCx, (uint32_t)(handle->stcSdCardInfo.u32RelativeCardAddr << 16U),
                                &handle->u32ErrorCode);
    if (LL_OK != i32Ret) {
        return i32Ret;
    }
    /* Configure the SD data transfer */
    stcDataCfg.u16BlockSize     = 8U;
    stcDataCfg.u16BlockCount    = 1U;
    stcDataCfg.u16TransDir      = SDIOC_TRANS_DIR_TO_HOST;
    stcDataCfg.u16AutoCmd12     = SDIOC_AUTO_SEND_CMD12_DISABLE;
    stcDataCfg.u16TransMode     = SDIOC_TRANS_MD_SINGLE;
    stcDataCfg.u16DataTimeout   = SDIOC_DATA_TIMEOUT_CLK_2E27;
    (void)SDIOC_ConfigData(handle->SDIOCx, &stcDataCfg);
    /* Send ACMD51 SD_APP_SEND_SCR with argument as 0 */
    i32Ret = SDMMC_ACMD51_SendSCR(handle->SDIOCx, &handle->u32ErrorCode);
    if (LL_OK != i32Ret) {
        return i32Ret;
    }

    i32Ret = SD_ReadWriteFifo(handle, &stcDataCfg, (uint8_t *)(&u32TempSCR[0]), SDMMC_DATA_TIMEOUT);
    if (LL_OK != i32Ret) {
        return i32Ret;
    }
    pu32SCR[1] = ((u32TempSCR[0] & 0x000000FFUL) << 24U) | ((u32TempSCR[0] & 0x0000FF00UL) << 8U) |
                 ((u32TempSCR[0] & 0x00FF0000UL) >> 8U)  | ((u32TempSCR[0] & 0xFF000000UL) >> 24U);
    pu32SCR[0] = ((u32TempSCR[1] & 0x000000FFUL) << 24U) | ((u32TempSCR[1] & 0x0000FF00UL) << 8U) |
                 ((u32TempSCR[1] & 0x00FF0000UL) >> 8U)  | ((u32TempSCR[1] & 0xFF000000UL) >> 24U);

    return i32Ret;
}

/**
 * @brief  Get the current card status.
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @param  [out] pu32CardStatus         Pointer to the value of current card status
 * @retval int32_t:
 *           - LL_OK: Get card status success
 *           - LL_ERR: Refer to u32ErrorCode for the reason of error
 *           - LL_ERR_INVD_PARAM: An invalid parameter was write to the send command
 *           - LL_ERR_TIMEOUT: Send command timeout
 */
int32_t SD_GetCurrCardStatus(stc_sd_handle_t *handle, uint32_t *pu32CardStatus)
{
    int32_t i32Ret;

    /* Send Status command */
    i32Ret = SDMMC_CMD13_SendStatus(handle->SDIOCx, (uint32_t)(handle->stcSdCardInfo.u32RelativeCardAddr << 16U),
                                    &handle->u32ErrorCode);
    if (LL_OK != i32Ret) {
        return i32Ret;
    }
    /* Get SD card status */
    (void)SDIOC_GetResponse(handle->SDIOCx, SDIOC_RESP_REG_BIT0_31, pu32CardStatus);

    return i32Ret;
}

/**
 * @brief  Read or Write the SD Card FIFO.
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @param  [in] pstcDataConfig          Pointer to a @ref stc_sdioc_data_config_t structure
 * @param  [out] pu8Data                Pointer to the value of read/write fifo
 * @param  [in] u32Timeout              The timeout time
 * @retval int32_t:
 *           - LL_OK: Read or Write the FIFO success
 *           - LL_ERR: Refer to u32ErrorCode for the reason of error
 *           - LL_ERR_INVD_PARAM: An invalid parameter was write to the send command
 *           - LL_ERR_TIMEOUT: Send command timeout
 */
int32_t SD_ReadWriteFifo(stc_sd_handle_t *handle, const stc_sdioc_data_config_t *pstcDataConfig,
                                uint8_t pu8Data[], uint32_t u32Timeout)
{
    __IO uint32_t u32Count;
    int32_t i32Ret = LL_OK;
    uint32_t u32Index = 0UL;

    /* The u32Timeout is expressed in ms */
    u32Count = u32Timeout * (HCLK_VALUE / 20000UL);
    while (RESET == SDIOC_GetIntStatus(handle->SDIOCx, (SDIOC_INT_FLAG_DEBE | SDIOC_INT_FLAG_DCE |
                                       SDIOC_INT_FLAG_DTOE | SDIOC_INT_FLAG_TC))) {
        if (SDIOC_TRANS_DIR_TO_CARD != pstcDataConfig->u16TransDir) {
            /* Read buffer data */
            if (SET == SDIOC_GetHostStatus(handle->SDIOCx, SDIOC_HOST_FLAG_BRE)) {
                (void)SDIOC_ReadBuffer(handle->SDIOCx, (uint8_t *)&pu8Data[u32Index],
                                       (uint32_t)(pstcDataConfig->u16BlockSize));
                u32Index += pstcDataConfig->u16BlockSize;
            }
        } else {
            /* Write buffer data */
            if (SET == SDIOC_GetHostStatus(handle->SDIOCx, SDIOC_HOST_FLAG_BWE)) {
                (void)SDIOC_WriteBuffer(handle->SDIOCx, (uint8_t *)&pu8Data[u32Index],
                                        (uint32_t)(pstcDataConfig->u16BlockSize));
                u32Index += pstcDataConfig->u16BlockSize;
            }
        }
        if (0UL == u32Count) {
            SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
            return LL_ERR_TIMEOUT;
        }
        u32Count--;
    }

    /* Send stop transmission command in case of multiblock read/write */
    if ((SET == SDIOC_GetIntStatus(handle->SDIOCx, SDIOC_INT_FLAG_TC)) && (pstcDataConfig->u16BlockCount > 1U)) {
        if (SD_CARD_SECURED != handle->stcSdCardInfo.u32CardType) {
            /* Send stop transmission command */
            i32Ret = SDMMC_CMD12_StopTrans(handle->SDIOCx, &handle->u32ErrorCode);
            if (LL_OK != i32Ret) {
                SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
                return i32Ret;
            }
        }
    }

    /* Get error state */
    if (SET == SDIOC_GetIntStatus(handle->SDIOCx, SDIOC_INT_FLAG_DEBE)) {
        SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
        handle->u32ErrorCode |= SDMMC_ERR_DATA_STOP_BIT;
        return LL_ERR;
    } else if (SET == SDIOC_GetIntStatus(handle->SDIOCx, SDIOC_INT_FLAG_DCE)) {
        SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
        handle->u32ErrorCode |= SDMMC_ERR_DATA_CRC_FAIL;
        return LL_ERR;
    } else if (SET == SDIOC_GetIntStatus(handle->SDIOCx, SDIOC_INT_FLAG_DTOE)) {
        SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
        handle->u32ErrorCode |= SDMMC_ERR_DATA_TIMEOUT;
        return LL_ERR;
    } else {
        /* Empty FIFO if there is still any data */
        if (SDIOC_TRANS_DIR_TO_CARD != pstcDataConfig->u16TransDir) {
            u32Count = u32Timeout * (HCLK_VALUE / 20000UL);
            while (SET == SDIOC_GetHostStatus(handle->SDIOCx, SDIOC_HOST_FLAG_BRE)) {
                (void)SDIOC_ReadBuffer(handle->SDIOCx, (uint8_t *)&pu8Data[u32Index],
                                       (uint32_t)(pstcDataConfig->u16BlockSize));
                u32Index += pstcDataConfig->u16BlockSize;
                if (0UL == u32Count) {
                    SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
                    return LL_ERR_TIMEOUT;
                }
                u32Count--;
            }
        }
        /* Clear all the error and completed flags */
        SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
    }

    return i32Ret;
}

/**
 * @brief  Set the bus width of the SD card.
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @retval int32_t:
 *           - LL_OK: Set bus width success
 *           - LL_ERR: Refer to u32ErrorCode for the reason of error
 *           - LL_ERR_INVD_PARAM: An invalid parameter was write to the send command
 *           - LL_ERR_TIMEOUT: Send command timeout
 */
int32_t SD_SetBusWidth(stc_sd_handle_t *handle)
{
    int32_t i32Ret;
    uint32_t u32BusWidth;

    if (SD_CARD_SECURED != handle->stcSdCardInfo.u32CardType) {
        if (SDIOC_BUS_WIDTH_1BIT == handle->stcSdiocInit.u8BusWidth) {
            u32BusWidth = 0UL;      /* 1 Bit */
        } else if (SDIOC_BUS_WIDTH_4BIT == handle->stcSdiocInit.u8BusWidth) {
            u32BusWidth = 2UL;      /* 4 Bit */
        } else {
            return LL_ERR_INVD_PARAM;
        }
    } else {
        /* MMC Card does not support this feature */
        handle->u32ErrorCode |= SDMMC_ERR_UNSUPPORT_FEATURE;
        return LL_ERR;
    }

    /* Supports wide bus or 1 bit mode operation */
    if ((SDMMC_SCR_BUS_WIDTH_4BIT == (handle->u32SCR[1] & SDMMC_SCR_BUS_WIDTH_4BIT)) ||
        (SDMMC_SCR_BUS_WIDTH_1BIT == (handle->u32SCR[1] & SDMMC_SCR_BUS_WIDTH_1BIT))) {
        /* Send CMD55 APP_CMD with argument as card's RCA.*/
        i32Ret = SDMMC_CMD55_AppCmd(handle->SDIOCx, (uint32_t)(handle->stcSdCardInfo.u32RelativeCardAddr << 16U),
                                    &handle->u32ErrorCode);
        if (LL_OK != i32Ret) {
            return i32Ret;
        }
        /* Send ACMD6 APP_CMD with argument */
        i32Ret = SDMMC_ACMD6_SetBusWidth(handle->SDIOCx, u32BusWidth, &handle->u32ErrorCode);
        if (LL_OK != i32Ret) {
            return i32Ret;
        }
    } else {
        handle->u32ErrorCode |= SDMMC_ERR_REQ_NOT_APPLICABLE;
        return LL_ERR;
    }
    /* Set the bus width of SDIOC */
    SDIOC_SetBusWidth(handle->SDIOCx, handle->stcSdiocInit.u8BusWidth);

    return i32Ret;
}

/**
 * @brief  Set the speed mode of the SD card.
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @retval int32_t:
 *           - LL_OK: Set speed mode success
 *           - LL_ERR: Refer to u32ErrorCode for the reason of error
 *           - LL_ERR_INVD_PARAM: An invalid parameter was write to the send command
 *           - LL_ERR_TIMEOUT: Send command timeout
 */
int32_t SD_SetSpeedMode(stc_sd_handle_t *handle)
{
    int32_t i32Ret = LL_OK;
    stc_sdioc_data_config_t stcDataCfg;
    uint32_t u32SDStatus[16];
    uint16_t u16Grp1Func;

    if (SD_CARD_SECURED != handle->stcSdCardInfo.u32CardType) {
        if (SDIOC_SPEED_MD_HIGH == handle->stcSdiocInit.u8SpeedMode) {
            /* Supports Specification version V1.1 or V2.0 */
            if ((SDMMC_SCR_PHY_SPEC_VER_1P1 == (handle->u32SCR[1] & SDMMC_SCR_PHY_SPEC_VER_1P1)) ||
                (SDMMC_SCR_PHY_SPEC_VER_2P0 == (handle->u32SCR[1] & SDMMC_SCR_PHY_SPEC_VER_2P0))) {
                /* Set Block Size To 64 Bytes */
                i32Ret = SDMMC_CMD16_SetBlockLength(handle->SDIOCx, 64UL, &handle->u32ErrorCode);
                if (LL_OK != i32Ret) {
                    return i32Ret;
                }
                /* Configure the SD data transfer */
                stcDataCfg.u16BlockSize    = 64U;
                stcDataCfg.u16BlockCount   = 1U;
                stcDataCfg.u16TransDir  = SDIOC_TRANS_DIR_TO_HOST;
                stcDataCfg.u16AutoCmd12  = SDIOC_AUTO_SEND_CMD12_DISABLE;
                stcDataCfg.u16TransMode = SDIOC_TRANS_MD_SINGLE;
                stcDataCfg.u16DataTimeout  = SDIOC_DATA_TIMEOUT_CLK_2E27;
                (void)SDIOC_ConfigData(handle->SDIOCx, &stcDataCfg);
                /* Send CMD6 SWITCH_FUNC with argument */
                i32Ret = SDMMC_CMD6_SwitchFunc(handle->SDIOCx, SD_SET_FUNC_HIGH_SPEED, &handle->u32ErrorCode);
                if (LL_OK != i32Ret) {
                    return i32Ret;
                }

                /* Get status data */
                i32Ret = SD_ReadWriteFifo(handle, &stcDataCfg, (uint8_t *)(&u32SDStatus[0]), SDMMC_DATA_TIMEOUT);
                if (LL_OK != i32Ret) {
                    return i32Ret;
                }
                /* Check the result of switch function */
                u16Grp1Func = (uint16_t)(((u32SDStatus[3] & 0x000000FFUL) << 8U) |
                                         ((u32SDStatus[3] & 0x0000FF00UL) >> 8U));
                if (SD_CMD6_RESULT_FUNC_GRP_BIT1 != (u16Grp1Func & SD_CMD6_RESULT_FUNC_GRP_BIT1)) {
                    handle->u32ErrorCode |= SDMMC_ERR_SWITCH_ERR;
                    return LL_ERR;
                }
            } else {
                handle->u32ErrorCode |= SDMMC_ERR_REQ_NOT_APPLICABLE;
                return LL_ERR;
            }
        }
    } else {
        /* MMC Card does not support this feature */
        handle->u32ErrorCode |= SDMMC_ERR_UNSUPPORT_FEATURE;
        return LL_ERR;
    }
    /* Set the clock division and speed mode of SDIOC */
    SDIOC_SetSpeedMode(handle->SDIOCx, handle->stcSdiocInit.u8SpeedMode);
    SDIOC_SetClockDiv(handle->SDIOCx, handle->stcSdiocInit.u16ClockDiv);

    return i32Ret;
}

/**
 * @brief  This function handles SD card interrupt request.
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @retval None
 */
void SD_IRQHandler(stc_sd_handle_t *handle)
{
    int32_t i32Ret;
    en_sd_card_state_t enCardState = SD_CARD_STAT_IDLE;
    en_functional_state_t enTransState;
    en_functional_state_t enReceiveState;

    enTransState   = SDIOC_GetIntEnableState(handle->SDIOCx, SDIOC_INT_BWRSEN);
    enReceiveState = SDIOC_GetIntEnableState(handle->SDIOCx, SDIOC_INT_BRRSEN);
    /* Check for SDIO interrupt flags */
    if (RESET != SDIOC_GetIntStatus(handle->SDIOCx, SDIOC_INT_FLAG_TC)) {
        SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_FLAG_TC);
        SDIOC_IntCmd(handle->SDIOCx, (SDIOC_INT_DEBESEN | SDIOC_INT_DCESEN | SDIOC_INT_DTOESEN |
                                      SDIOC_INT_TCSEN   | SDIOC_INT_BRRSEN | SDIOC_INT_BWRSEN), DISABLE);
        if ((0UL != (handle->u32Context & SD_CONTEXT_INT)) || (0UL != (handle->u32Context & SD_CONTEXT_DMA))) {
            if ((0UL != (handle->u32Context & SD_CONTEXT_WR_MULTI_BLOCK)) ||
                (0UL != (handle->u32Context & SD_CONTEXT_RD_MULTI_BLOCK))) {
                /* Send stop transmission command */
                i32Ret = SDMMC_CMD12_StopTrans(handle->SDIOCx, &handle->u32ErrorCode);
                if (LL_OK != i32Ret) {
                    SD_ErrorCallback(handle);
                }
            }
            SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
            if ((0UL != (handle->u32Context & SD_CONTEXT_WR_SINGLE_BLOCK)) ||
                (0UL != (handle->u32Context & SD_CONTEXT_WR_MULTI_BLOCK))) {
                SD_TxCompleteCallback(handle);
            } else {
                SD_RxCompleteCallback(handle);
            }
        }
    } else if ((RESET != SDIOC_GetHostStatus(handle->SDIOCx, SDIOC_HOST_FLAG_BWE)) &&
               (DISABLE != enTransState)) {
        (void)SDIOC_WriteBuffer(handle->SDIOCx, handle->pu8Buffer, 4UL);
        handle->pu8Buffer += 4U;
        handle->u32Len -= 4U;
        if (0UL == handle->u32Len) {
            SDIOC_IntCmd(handle->SDIOCx, SDIOC_INT_BWRSEN, DISABLE);
        }
    } else if ((RESET != SDIOC_GetHostStatus(handle->SDIOCx, SDIOC_HOST_FLAG_BRE)) &&
               (DISABLE != enReceiveState)) {
        (void)SDIOC_ReadBuffer(handle->SDIOCx, handle->pu8Buffer, 4UL);
        handle->pu8Buffer += 4U;
        handle->u32Len -= 4U;
        if (0UL == handle->u32Len) {
            SDIOC_IntCmd(handle->SDIOCx, SDIOC_INT_BRRSEN, DISABLE);
        }
    } else if (RESET != SDIOC_GetIntStatus(handle->SDIOCx, (SDIOC_INT_DEBESEN |
                                           SDIOC_INT_DCESEN | SDIOC_INT_DTOESEN))) {
        /* Set LL_ERR code */
        if (RESET != SDIOC_GetIntStatus(handle->SDIOCx, SDIOC_INT_DEBESEN)) {
            handle->u32ErrorCode |= SDMMC_ERR_DATA_STOP_BIT;
        }
        if (RESET != SDIOC_GetIntStatus(handle->SDIOCx, SDIOC_INT_DCESEN)) {
            handle->u32ErrorCode |= SDMMC_ERR_DATA_CRC_FAIL;
        }
        if (RESET != SDIOC_GetIntStatus(handle->SDIOCx, SDIOC_INT_DTOESEN)) {
            handle->u32ErrorCode |= SDMMC_ERR_DATA_TIMEOUT;
        }

        /* Clear All flags */
        SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
        /* Disable all interrupts */
        SDIOC_IntCmd(handle->SDIOCx, (SDIOC_INT_DEBESEN | SDIOC_INT_DCESEN | SDIOC_INT_DTOESEN |
                                      SDIOC_INT_TCSEN   | SDIOC_INT_BRRSEN | SDIOC_INT_BWRSEN), DISABLE);
        if (0UL != (handle->u32Context & SD_CONTEXT_INT)) {
            SD_ErrorCallback(handle);
        } else if (0UL != (handle->u32Context & SD_CONTEXT_DMA)) {
            if (NULL != handle->DMAx) {
                /* Disable the DMA Channel */
                if ((0UL != (handle->u32Context & SD_CONTEXT_WR_SINGLE_BLOCK)) ||
                    (0UL != (handle->u32Context & SD_CONTEXT_WR_MULTI_BLOCK))) {
                    (void)DMA_ChCmd(handle->DMAx, handle->u8DmaTxCh, DISABLE);
                } else {
                    (void)DMA_ChCmd(handle->DMAx, handle->u8DmaRxCh, DISABLE);
                }
                /* Stop SD transfer */
                (void)SD_GetCardState(handle, &enCardState);
                handle->u32ErrorCode = SDMMC_ERR_NONE;
                if ((SD_CARD_STAT_TX_DATA == enCardState) || (SD_CARD_STAT_RX_DATA == enCardState)) {
                    /* Send stop transmission command */
                    (void)SDMMC_CMD12_StopTrans(handle->SDIOCx, &handle->u32ErrorCode);
                }
                SD_ErrorCallback(handle);
            }
        } else {
        }
    } else {
    }
}

/**
 * @brief  Get the current sd card state.
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @param  [out] peCardState            Pointer to a @ref en_sd_card_state_t enumeration
 * @retval int32_t:
 *           - LL_OK: Get sd card state success
 *           - LL_ERR: Refer to u32ErrorCode for the reason of error
 *           - LL_ERR_INVD_PARAM: handle == NULL or peCardState == NULL or
 *                                An invalid parameter was write to the send command
 *           - LL_ERR_TIMEOUT: Send command timeout
 */
int32_t SD_GetCardState(stc_sd_handle_t *handle, en_sd_card_state_t *peCardState)
{
    int32_t i32Ret;
    uint32_t u32Response = 0UL;

    if ((NULL == peCardState) || (NULL == handle)) {
        i32Ret = LL_ERR_INVD_PARAM;
    } else {
        i32Ret = SD_GetCurrCardStatus(handle, &u32Response);
        *peCardState = (en_sd_card_state_t)(uint32_t)((u32Response >> SDMMC_STATUS_CURR_STATE_POS) & 0x0FU);
    }

    return i32Ret;
}

/**
 * @brief  SD card erase.
 * @param  None
 * @retval int32_t:
 *           - LL_OK: SD card erase success
 *           - LL_ERR: SD card erase error
 */
int32_t SdCard_Erase(void)
{
    uint32_t i;
    int32_t i32Ret = LL_OK;

    /* Initialize read/write blocks */
    (void)memset(u8ReadBlocks, 0x20, (SD_CARD_BLK_SIZE * SD_CARD_BLK_NUM));
    /* Erase SD card */
    if (LL_OK != SD_Erase(&SdHandle, 0UL, SD_CARD_BLK_NUM)) {
        i32Ret = LL_ERR;
    }

    /* Read SD card */

    u8RxCompleteFlag = 0U;
    if (LL_OK != SD_ReadBlocks_DMA(&SdHandle, 0UL, SD_CARD_BLK_NUM, (uint8_t *)u8ReadBlocks)) {
        i32Ret = LL_ERR;
    }
    /* Wait for transfer completed */
    while ((0U == u8RxCompleteFlag) && (0U == u8TxRxErrorFlag)) {
    }


//    /* Check whether data value is OxFF or 0x00 after erase SD card */
//    for (i = 0UL; i < (SD_CARD_BLK_SIZE * SD_CARD_BLK_NUM); i++) {
//        if ((0x00U != u8ReadBlocks[i]) && (0xFFU != u8ReadBlocks[i])) {
//            i32Ret = LL_ERR;
//            break;
//        }
//    }

//    if (LL_OK != i32Ret) {
//        DDL_Printf("SD card erase failed!\r\n");
//    }

    return i32Ret;
}

/**
 * @brief  Erases the specified memory area of the given SD card.
 * @note   This API should be followed by a check on the card state through SD_GetCardState().
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @param  [in] u32BlockStartAddr       Start Block address
 * @param  [in] u32BlockEndAddr         End Block address
 * @retval int32_t:
 *           - LL_OK: Erases the SD card success
 *           - LL_ERR: Refer to u32ErrorCode for the reason of error
 *           - LL_ERR_INVD_PARAM: handle == NULL or An invalid parameter was write to the send command
 *           - LL_ERR_TIMEOUT: Send command timeout
 */
int32_t SD_Erase(stc_sd_handle_t *handle, uint32_t u32BlockStartAddr, uint32_t u32BlockEndAddr)
{
    int32_t i32Ret;
    uint32_t u32CardSta = 0UL;

    if ((u32BlockEndAddr < u32BlockStartAddr) || (NULL == handle)) {
        i32Ret = LL_ERR_INVD_PARAM;
    } else {
        if (u32BlockEndAddr > (handle->stcSdCardInfo.u32LogBlockNum)) {
            handle->u32ErrorCode |= SDMMC_ERR_ADDR_OUT_OF_RANGE;
            return LL_ERR;
        }
        /* Check if the card command class supports erase command */
        if (0UL == ((handle->stcSdCardInfo.u32Class) & SDMMC_CSD_SUPPORT_CLASS5_ERASE)) {
            handle->u32ErrorCode |= SDMMC_ERR_REQ_NOT_APPLICABLE;
            return LL_ERR;
        }
        /* Check the lock status */
        i32Ret = SD_GetCurrCardStatus(handle, &u32CardSta);
        if (LL_OK != i32Ret) {
            return i32Ret;
        }
        if (SDMMC_STATUS_CARD_IS_LOCKED == (u32CardSta & SDMMC_STATUS_CARD_IS_LOCKED)) {
            handle->u32ErrorCode |= SDMMC_ERR_LOCK_UNLOCK_FAILED;
            return LL_ERR;
        }
        /* Get start and end block for high capacity cards */
        if (SD_CARD_SDHC_SDXC != handle->stcSdCardInfo.u32CardType) {
            u32BlockStartAddr *= 512U;
            u32BlockEndAddr   *= 512U;
        }

        /* According to sd-card spec 1.0 ERASE_GROUP_START (CMD32) and erase_group_end(CMD33) */
        if (SD_CARD_SECURED != handle->stcSdCardInfo.u32CardType) {
            /* Send CMD32 ERASE_WR_BLK_START with argument as addr  */
            i32Ret = SDMMC_CMD32_EraseBlockStartAddr(handle->SDIOCx, u32BlockStartAddr, &handle->u32ErrorCode);
            if (LL_OK != i32Ret) {
                SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
                return i32Ret;
            }
            /* Send CMD33 ERASE_WR_BLK_END with argument as addr  */
            i32Ret = SDMMC_CMD33_EraseBlockEndAddr(handle->SDIOCx, u32BlockEndAddr, &handle->u32ErrorCode);
            if (LL_OK != i32Ret) {
                SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
                return i32Ret;
            }
        }
        /* Send CMD38 ERASE */
        i32Ret = SDMMC_CMD38_Erase(handle->SDIOCx, &handle->u32ErrorCode);
        if (LL_OK != i32Ret) {
            SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
            return i32Ret;
        }
    }

    return i32Ret;
}

/**
 * @brief  Reads block(s) from a specified address in a card.
 * @note   The Data transfer is managed by DMA mode.
 * @note   This API should be followed by a check on the card state through SD_GetCardState().
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @param  [in] u32BlockAddr            Block Address
 * @param  [in] u16BlockCount           Block Count
 * @param  [out] pu8Data                Pointer to the buffer that will contain the received data
 * @retval int32_t:
 *           - LL_OK: Read block(s) success
 *           - LL_ERR: Refer to u32ErrorCode for the reason of error
 *           - LL_ERR_INVD_PARAM: handle == NULL or pu8Data == NULL or NULL == handle->DMAx or
 *                                    An invalid parameter was write to the send command
 *           - LL_ERR_TIMEOUT: Send command timeout
 */
int32_t SD_ReadBlocks_DMA(stc_sd_handle_t *handle, uint32_t u32BlockAddr, uint16_t u16BlockCount, uint8_t *pu8Data)
{
    int32_t i32Ret;
    stc_sdioc_data_config_t stcDataCfg;

    if ((NULL == pu8Data) || (NULL == handle) || (NULL == handle->DMAx) || (0U != ((uint32_t)pu8Data % 4U))) {
        i32Ret = LL_ERR_INVD_PARAM;
    } else {
        handle->u32ErrorCode = SDMMC_ERR_NONE;
        if ((u32BlockAddr + u16BlockCount) > (handle->stcSdCardInfo.u32LogBlockNum)) {
            handle->u32ErrorCode |= SDMMC_ERR_ADDR_OUT_OF_RANGE;
            return LL_ERR;
        }
        if (SD_CARD_SDHC_SDXC != handle->stcSdCardInfo.u32CardType) {
            u32BlockAddr *= 512U;
        }

        /* Set Block Size for Card */
        i32Ret = SDMMC_CMD16_SetBlockLength(handle->SDIOCx, SD_CARD_BLOCK_SIZE, &handle->u32ErrorCode);
        if (LL_OK != i32Ret) {
            SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
            return i32Ret;
        }
        /* Enable SDIOC transfer complete and errors interrupt */
        SDIOC_IntCmd(handle->SDIOCx, (SDIOC_INT_TCSEN  | SDIOC_INT_DEBESEN |
                                      SDIOC_INT_DCESEN | SDIOC_INT_DTOESEN), ENABLE);
        /* Configure DMA parameters */
        SD_DmaTransConfig(handle, handle->u8DmaRxCh, (uint32_t)(&handle->SDIOCx->BUF0), (uint32_t)pu8Data,
                          (SD_CARD_BLOCK_SIZE / 4U), u16BlockCount);
        /* Enable the DMA Channel */
        (void)DMA_ChCmd(handle->DMAx, handle->u8DmaRxCh, ENABLE);
        /* Configure the SD data transfer */
        stcDataCfg.u16BlockSize     = SD_CARD_BLOCK_SIZE;
        stcDataCfg.u16BlockCount    = u16BlockCount;
        stcDataCfg.u16TransDir      = SDIOC_TRANS_DIR_TO_HOST;
        stcDataCfg.u16AutoCmd12     = SDIOC_AUTO_SEND_CMD12_DISABLE;
        stcDataCfg.u16DataTimeout   = SDIOC_DATA_TIMEOUT_CLK_2E27;
        stcDataCfg.u16TransMode     = (u16BlockCount > 1U) ? (uint16_t)SDIOC_TRANS_MD_MULTI :
                                      (uint16_t)SDIOC_TRANS_MD_SINGLE;
        (void)SDIOC_ConfigData(handle->SDIOCx, &stcDataCfg);
        /* Read block(s) in DMA mode */
        if (u16BlockCount > 1U) {
            handle->u32Context = SD_CONTEXT_RD_MULTI_BLOCK | SD_CONTEXT_DMA;
            /* Read Multi Block command */
            i32Ret = SDMMC_CMD18_ReadMultipleBlock(handle->SDIOCx, u32BlockAddr, &handle->u32ErrorCode);
        } else {
            handle->u32Context = SD_CONTEXT_RD_SINGLE_BLOCK | SD_CONTEXT_DMA;
            /* Read Single Block command */
            i32Ret = SDMMC_CMD17_ReadSingleBlock(handle->SDIOCx, u32BlockAddr, &handle->u32ErrorCode);
        }

        if (LL_OK != i32Ret) {
            SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
            return i32Ret;
        }
    }

    return i32Ret;
}

/**
 * @brief  Configure the Dma transfer parameters.
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @param  [in] u8Ch                    DMA transfer channel
 * @param  [in] u32SrcAddr              Source Address
 * @param  [in] u32DestAddr             Destination Address
 * @param  [in] u16BlockSize            Block Size
 * @param  [in] u16TransCount           Transfer Count
 * @retval None
 */
void SD_DmaTransConfig(const stc_sd_handle_t *handle, uint8_t u8Ch, uint32_t u32SrcAddr, uint32_t u32DestAddr,
                              uint16_t u16BlockSize, uint16_t u16TransCount)
{
    /* Stop Configure channel */
    (void)DMA_ChCmd(handle->DMAx, u8Ch, DISABLE);
    DMA_ClearTransCompleteStatus(handle->DMAx, (uint32_t)(0x1UL << u8Ch));

    /* Config DMA source and destination address */
    DMA_SetSrcAddr(handle->DMAx, u8Ch, u32SrcAddr);
    DMA_SetDestAddr(handle->DMAx, u8Ch, u32DestAddr);
    /* Config DMA block size and transfer count */
    DMA_SetBlockSize(handle->DMAx, u8Ch, u16BlockSize);
    DMA_SetTransCount(handle->DMAx, u8Ch, u16TransCount);
}

/**
 * @brief  SD card multi-block read/write.
 * @param  None
 * @retval int32_t:
 *           - LL_OK: SD card multi-block read/write success
 *           - LL_ERR: SD card multi-block read/write error
 */
int32_t SdCard_RdWrMultiBlock(void)
{
    int32_t i32Ret = LL_OK;

    /* Initialize read/write blocks */
    (void)memset(u8WriteBlocks, 0x20, (SD_CARD_BLK_SIZE * SD_CARD_BLK_NUM));
    (void)memset(u8ReadBlocks,  0, (SD_CARD_BLK_SIZE * SD_CARD_BLK_NUM));
    /* Write SD card */

    u8TxCompleteFlag = 0U;
    if (LL_OK != SD_WriteBlocks_DMA(&SdHandle, 0UL, SD_CARD_BLK_NUM, (uint8_t *)u8WriteBlocks)) {
        i32Ret = LL_ERR;
    }
    /* Wait for transfer completed */
    while ((0U == u8TxCompleteFlag) && (0U == u8TxRxErrorFlag)) {
    }

    /* Read SD card */

    u8RxCompleteFlag = 0U;
    if (LL_OK != SD_ReadBlocks_DMA(&SdHandle, 0UL, SD_CARD_BLK_NUM, (uint8_t *)u8ReadBlocks)) {
        i32Ret = LL_ERR;
    }
    /* Wait for transfer completed */
    while ((0U == u8RxCompleteFlag) && (0U == u8TxRxErrorFlag)) {
    }

    /* Check data value */
    if (0 != memcmp(u8WriteBlocks, u8ReadBlocks, (SD_CARD_BLK_SIZE * SD_CARD_BLK_NUM))) {
        i32Ret = LL_ERR;
    }

    if (LL_OK != i32Ret) {
        DDL_Printf("SD card multi-block read/write failed!\r\n");
    }

    return i32Ret;
}

/**
 * @brief  Write block(s) to a specified address in a card.
 * @note   The Data transfer is managed by DMA mode.
 * @note   This API should be followed by a check on the card state through SD_GetCardState().
 * @param  [in] handle                  Pointer to a @ref stc_sd_handle_t structure
 * @param  [in] u32BlockAddr            Block Address
 * @param  [in] u16BlockCount           Block Count
 * @param  [in] pu8Data                 Pointer to the buffer that will contain the data to transmit
 * @retval int32_t:
 *           - LL_OK: Write block(s) success
 *           - LL_ERR: Refer to u32ErrorCode for the reason of error
 *           - LL_ERR_INVD_PARAM: handle == NULL or pu8Data == NULL or NULL == handle->DMAx or
 *                                An invalid parameter was write to the send command
 *           - LL_ERR_TIMEOUT: Send command timeout
 */
int32_t SD_WriteBlocks_DMA(stc_sd_handle_t *handle, uint32_t u32BlockAddr, uint16_t u16BlockCount, uint8_t *pu8Data)
{
    int32_t i32Ret;
    stc_sdioc_data_config_t stcDataCfg;

    if ((NULL == pu8Data) || (NULL == handle) || (NULL == handle->DMAx) || (0U != ((uint32_t)pu8Data % 4U))) {
        i32Ret = LL_ERR_INVD_PARAM;
    } else {
        handle->u32ErrorCode = SDMMC_ERR_NONE;
        if ((u32BlockAddr + u16BlockCount) > (handle->stcSdCardInfo.u32LogBlockNum)) {
            handle->u32ErrorCode |= SDMMC_ERR_ADDR_OUT_OF_RANGE;
            return LL_ERR;
        }
        if (SD_CARD_SDHC_SDXC != handle->stcSdCardInfo.u32CardType) {
            u32BlockAddr *= 512U;
        }

        /* Set Block Size for Card */
        i32Ret = SDMMC_CMD16_SetBlockLength(handle->SDIOCx, SD_CARD_BLOCK_SIZE, &handle->u32ErrorCode);
        if (LL_OK != i32Ret) {
            SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
            return i32Ret;
        }
        /* Enable SDIOC transfer complete and errors interrupt */
        SDIOC_IntCmd(handle->SDIOCx, (SDIOC_INT_TCSEN  | SDIOC_INT_DEBESEN |
                                      SDIOC_INT_DCESEN | SDIOC_INT_DTOESEN), ENABLE);
        /* Configure DMA parameters */
        SD_DmaTransConfig(handle, handle->u8DmaTxCh, (uint32_t)pu8Data, (uint32_t)(&handle->SDIOCx->BUF0),
                          (SD_CARD_BLOCK_SIZE / 4U), u16BlockCount);
        /* Enable the DMA Channel */
        (void)DMA_ChCmd(handle->DMAx, handle->u8DmaTxCh, ENABLE);
        /* Configure the SD data transfer */
        stcDataCfg.u16BlockSize     = SD_CARD_BLOCK_SIZE;
        stcDataCfg.u16BlockCount    = u16BlockCount;
        stcDataCfg.u16TransDir      = SDIOC_TRANS_DIR_TO_CARD;
        stcDataCfg.u16AutoCmd12     = SDIOC_AUTO_SEND_CMD12_DISABLE;
        stcDataCfg.u16DataTimeout   = SDIOC_DATA_TIMEOUT_CLK_2E27;
        stcDataCfg.u16TransMode     = (u16BlockCount > 1U) ? (uint16_t)SDIOC_TRANS_MD_MULTI :
                                      (uint16_t)SDIOC_TRANS_MD_SINGLE;
        (void)SDIOC_ConfigData(handle->SDIOCx, &stcDataCfg);
        /* Write block(s) in DMA mode */
        if (u16BlockCount > 1U) {
            handle->u32Context = SD_CONTEXT_WR_MULTI_BLOCK | SD_CONTEXT_DMA;
            /* Write Multi Block command */
            i32Ret = SDMMC_CMD25_WriteMultipleBlock(handle->SDIOCx, u32BlockAddr, &handle->u32ErrorCode);
        } else {
            handle->u32Context = SD_CONTEXT_WR_SINGLE_BLOCK | SD_CONTEXT_DMA;
            /* Write Single Block command */
            i32Ret = SDMMC_CMD24_WriteSingleBlock(handle->SDIOCx, u32BlockAddr, &handle->u32ErrorCode);
        }

        if (LL_OK != i32Ret) {
            SDIOC_ClearIntStatus(handle->SDIOCx, SDIOC_INT_STATIC_FLAGS);
            return i32Ret;
        }
    }

    return i32Ret;
}
